package view;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.border.EmptyBorder;

import model.Project;
import modelInterfaces.IProject;
import viewInterfaces.IViewMain;
import controller.ControllerMain;
import controllerInterfaces.IControllerMain;
import enums.Use;
import javax.swing.BoxLayout;
import javax.swing.border.EtchedBorder;

/**
 * 
 * MVC++ Main View Class.</br>
 * Presents main user interface with Recommender, Metrics, Test and Benchmark tabs,</br>
 * and actions to take over a {@link Project}
 * @see Project
 * @see ControllerMain 
 */
public class ViewMain extends JFrame implements IViewMain {

	/** MVC++ Main Controller 
	 * @see ControllerMain*/
	private IControllerMain myController;
	
	/**Main panel of frame*/
	private JPanel contentPane;
	
	/**tabbedPane contains recommender, metric, test and benchmark tabs */
	private JTabbedPane tabbedPane;
	
	/** Button for create a new project*/
	private JMenuItem mntmNewProject;
	
	/** Button for load a existing project*/
	private JMenuItem mntmLoadProject;
	
	/** Button for save a current project*/
	private JMenuItem mntmSaveProject;
	
	/** Button for save a copy of current project*/
	private JMenuItem mntmSaveProjectAs;
	
	/** Label indicates project file*/
	private JLabel lblProjectFile;
	
	/** Label indicates database status*/
	private JLabel lblDBStatus;
	
	/** Label indicates project status*/
	private JLabel lblProjectStatus;
	
	/** Title of window*/
	private String windowTitle = "";


	/**
	 * Class Constructor creates the frame.
	 */
	public ViewMain() {
		
		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				myController.close();
			}
		});
		setBounds(100, 100, 529, 461);
		
		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		
		JMenu mnFile = new JMenu("File");
		menuBar.add(mnFile);
		
		mntmNewProject = new JMenuItem("New Project");
		mntmNewProject.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				startProjectManagementToCreateByController();
			}
		});
		mnFile.add(mntmNewProject);
		
		mntmLoadProject = new JMenuItem("Load Project");
		mntmLoadProject.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				startProjectManagementToLoadByController();
			}
		});
		mnFile.add(mntmLoadProject);
		
		mntmSaveProject = new JMenuItem("Save Project");
		mntmSaveProject.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				startProjectManagementToSaveByController();
			}
		});
		mnFile.add(mntmSaveProject);
		
		mntmSaveProjectAs = new JMenuItem("Save Project as...");
		mntmSaveProjectAs.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				startProjectManagementToSaveAsByController();
			}
		});
		mnFile.add(mntmSaveProjectAs);
		
		JMenuItem mntmExit = new JMenuItem("Exit");
		mntmExit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				//close();
				myController.close();
			}
		});
		mnFile.add(mntmExit);
		
		JMenu mnDataset = new JMenu("DataSet");
		menuBar.add(mnDataset);
		
		JMenuItem mntmDbConnection = new JMenuItem("DB Connection");
		mnDataset.add(mntmDbConnection);
		mntmDbConnection.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				startDBConnectionSetup();
			}
		});
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		
		tabbedPane = new JTabbedPane(JTabbedPane.TOP);
		tabbedPane.setBorder(null);
		
		JPanel panelStatus = new JPanel();
		GroupLayout gl_contentPane = new GroupLayout(contentPane);
		gl_contentPane.setHorizontalGroup(
			gl_contentPane.createParallelGroup(Alignment.LEADING)
				.addComponent(panelStatus, GroupLayout.PREFERRED_SIZE, 503, Short.MAX_VALUE)
				.addComponent(tabbedPane, GroupLayout.DEFAULT_SIZE, 503, Short.MAX_VALUE)
		);
		gl_contentPane.setVerticalGroup(
			gl_contentPane.createParallelGroup(Alignment.TRAILING)
				.addGroup(gl_contentPane.createSequentialGroup()
					.addComponent(tabbedPane, GroupLayout.DEFAULT_SIZE, 315, Short.MAX_VALUE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(panelStatus, GroupLayout.PREFERRED_SIZE, 71, GroupLayout.PREFERRED_SIZE))
		);
		
		JLabel lblProjectFileLabel = new JLabel("Project File:");
		
		lblProjectFile = new JLabel("None");
		lblProjectFile.setEnabled(false);
		
		JLabel lblDBStatusLabel = new JLabel("DB Status:");
		
		lblDBStatus = new JLabel("Disconnected");
		lblDBStatus.setEnabled(false);
		
		lblProjectStatus = new JLabel("(Not open)");
		lblProjectStatus.setEnabled(false);
		GroupLayout gl_panelStatus = new GroupLayout(panelStatus);
		gl_panelStatus.setHorizontalGroup(
			gl_panelStatus.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_panelStatus.createSequentialGroup()
					.addContainerGap()
					.addGroup(gl_panelStatus.createParallelGroup(Alignment.LEADING, false)
						.addComponent(lblDBStatusLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
						.addComponent(lblProjectFileLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
					.addPreferredGap(ComponentPlacement.UNRELATED)
					.addGroup(gl_panelStatus.createParallelGroup(Alignment.LEADING)
						.addGroup(gl_panelStatus.createSequentialGroup()
							.addComponent(lblProjectFile)
							.addPreferredGap(ComponentPlacement.RELATED)
							.addComponent(lblProjectStatus, GroupLayout.PREFERRED_SIZE, 65, GroupLayout.PREFERRED_SIZE))
						.addComponent(lblDBStatus))
					.addGap(392))
		);
		gl_panelStatus.setVerticalGroup(
			gl_panelStatus.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_panelStatus.createSequentialGroup()
					.addContainerGap()
					.addGroup(gl_panelStatus.createParallelGroup(Alignment.BASELINE)
						.addComponent(lblProjectFileLabel)
						.addComponent(lblProjectFile)
						.addComponent(lblProjectStatus))
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(gl_panelStatus.createParallelGroup(Alignment.BASELINE)
						.addComponent(lblDBStatusLabel)
						.addComponent(lblDBStatus))
					.addContainerGap(15, Short.MAX_VALUE))
		);
		panelStatus.setLayout(gl_panelStatus);
		contentPane.setLayout(gl_contentPane);
	}


	/**
	 * Set the MVC++ Main Class for this View.</br>
	 * ControllerMain is manipulable through {@link IControllerMain} interface.
	 * @param	controller	MVC++ Main Controller.
	 * @see	ControllerMain
	 * @see IControllerMain
	 */
	public void SetController(IControllerMain controller) {
		this.myController = controller;
		this.windowTitle = myController.getRboxVersion();
	}

	
	/**
	 * Set and add the panel to {@link tabbedPane}.
	 * @param	name	panel name.
	 * @param	panel	panel to set and add in {@link tabbedPane}.
	 */	
	public void SetTabbedPane(String name, JPanel panel) {
		this.tabbedPane.addTab(name, panel);
	}


	/**
	 * Show the frame.
	 */
	public void render() {
		this.setVisible(true);
		this.setLocationRelativeTo(null);
	}


	/**
	 * Show error dialog.
	 * @param code	error code
	 * @param message	error message.
	 */	
	public void renderError(int code, String message) {
		javax.swing.JOptionPane.showMessageDialog(this, code + " - " + message, "Error",javax.swing.JOptionPane.ERROR_MESSAGE);
	}


	/**
	 * Show exit dialog.
	 */
	public void close() {
		
		if(this.myController.isModifiedProject())
		{
			Object[] options = { "Yes", "No", "Cancel" };
			int n = JOptionPane
					.showOptionDialog(
							null,
							"Do you want to save changes " + this.myController.getProject().getName()+ " project modified?",
							"Rbox",
							JOptionPane.YES_NO_CANCEL_OPTION,
							JOptionPane.WARNING_MESSAGE, null,
							options, options[1]);
			if (n == 0) {
				this.myController.startProjectManagement(Use.Save);
			}
			else if (n == 1)
			{
				this.myController.normalExit();
			}
		}
		else
		{
			Object[] options = { "Yes", "No" };
			int n = JOptionPane
					.showOptionDialog(
							null,
							"Are you sure you want to exit?",
							"Confirm Exit",
							JOptionPane.YES_NO_CANCEL_OPTION,
							JOptionPane.QUESTION_MESSAGE, null,
							options, options[1]);
			if (n == 0) {
				myController.normalExit();
			}
		}
		
		

	}




	/**
	 * Set frame title according to parameter name. 
	 * @param name	project name 
	 * @see Project
	 * @see IProject
	 */
	public void setProjectNameinFrame(String name) {
		this.setTitle(this.windowTitle + " - \"" + name + " Project\"");
	}



	/**
	 * Enable or disable button for create new project according to parameter value.
	 * @param value	True for enable to button. False for disable to button.
	 * @see Project
	 */	
	public void setNewProjectButtonEnabled(boolean value) {
		this.mntmNewProject.setEnabled(value);
	}


	/**
	 * Enable or disable button for load a existing project according to parameter value.
	 * @param value	True for enable to button. False for disable to button
	 * @see Project
	 */	
	public void setLoadProjectButtonEnabled(boolean value) {
		this.mntmLoadProject.setEnabled(value);
	}


	
	/**
	 * Enable or disable button for save a current project according to parameter value.
	 * @param value	True for enable to button. False for disable to button
	 * @see Project
	 */
	public void setSaveProjectButtonEnabled(boolean value) {
		this.mntmSaveProject.setEnabled(value);
	}

	
	
	/**
	 * Enable or disable button for save a new copy of current project according to parameter value.
	 * @param value	True for enable to button. False for disable to button
	 * @see Project
	 */	
	public void setSaveAsProjectButtonEnabled(boolean value) {
		this.mntmSaveProjectAs.setEnabled(value);
	}

	
	/**
	 * Set label of project status according to parameter str
	 * @param str string of project status
	 */	
	public void SetLabelProjectStatus(String str, boolean value) {
		this.lblProjectStatus.setText("("+ str + ")");
		this.lblProjectFile.setEnabled(value);
	}


	/**
	 * Set filename of project according to parameter str and value
	 * @param str filename of project
	 * @param value if it is true then label will be enabled, otherwise will be disabled
	 */	
	public void SetLabelFileName(String str, boolean value) {
		this.lblProjectFile.setText(str);
		this.lblProjectFile.setEnabled(value);
	}

	

	/**
	 * Set status of database connection according to parameters str and value.
	 * @param str status of database connection
	 * @param value if it is true (connected database) then label will be enabled, otherwise (disconnected database) will be disabled
	 */			
	public void setLabelDBStatus(String str, boolean value) {
		this.lblDBStatus.setText(str);
		this.lblDBStatus.setEnabled(value);
	}
	
	
	/**
	 * Start Project Management for create a new project.
	 */
	public void startProjectManagementToCreateByController()
	{
		if(this.myController.isModifiedProject())
		{
			Object[] options = { "Yes", "No", "Cancel" };
			int n = JOptionPane
					.showOptionDialog(
							null,
							"Do you want to save changes " + this.myController.getProject().getName()+ " project modified?",
							"Rbox",
							JOptionPane.YES_NO_CANCEL_OPTION,
							JOptionPane.WARNING_MESSAGE, null,
							options, options[1]);
			if (n == 0)
			{
				this.myController.startProjectManagement(Use.Save);
			}
			else if (n == 1)
			{
				this.myController.startProjectManagement(Use.New);
			}			
		}
		else
		{
			this.myController.startProjectManagement(Use.New);
		}
	}
	
	
	/**
	 * Start Project Management for load a existing project.
	 */
	public void startProjectManagementToLoadByController()
	{
		if(this.myController.isModifiedProject())
		{
			Object[] options = { "Yes", "No", "Cancel" };
			int n = JOptionPane
					.showOptionDialog(
							null,
							"Do you want to save changes " + this.myController.getProject().getName()+ " project modified?",
							"Rbox",
							JOptionPane.YES_NO_CANCEL_OPTION,
							JOptionPane.WARNING_MESSAGE, null,
							options, options[1]);
			if (n == 0)
			{
				this.myController.startProjectManagement(Use.Save);
			}
			else if (n == 1)
			{
				this.myController.startProjectManagement(Use.Load);
			}			
		}
		else
		{
			this.myController.startProjectManagement(Use.Load);
		}
	}	
	
	
	/**
	 * Start Project Management for save a current project.
	 */	
	public void startProjectManagementToSaveByController()
	{
		myController.startProjectManagement(Use.Save);
	}
	
	
	/**
	 * Start Project Management for save copy of a current project.
	 */	
	public void startProjectManagementToSaveAsByController()
	{
		myController.startProjectManagement(Use.SaveAs);
	}
	

	/**
	 * Start database connection setup.
	 */
	public void startDBConnectionSetup() {
		myController.startDBConnectionSetup();
	}
	
	
	/**
	 * Close application by controller.
	 */	
	public void closeByController()
	{
		myController.close();
	}		
	
}
